package com.insight.common.util;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

@Slf4j
public class MD5Util {

	private static final String[] hexDigits = {
			"0", "1", "2", "3", "4", "5",
			"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"
	};

	// 盐值长度（16字节 = 128位，可根据需求调整）
	private static final int SALT_LENGTH = 16;
	/**
	 * 生成随机Salt（使用强随机生成器）
	 */
	private static byte[] generateSalt() {
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[SALT_LENGTH];
		random.nextBytes(salt); // 生成强随机字节数组
		return salt;
	}


	/**
	 * 原始 MD5 加密（不加盐）
	 */
	public static String MD5Encode(String origin, String charsetname) {
		try {
			// 生成随机盐值
			byte[] salt = generateSalt();
			MessageDigest md = MessageDigest.getInstance("MD5");

			// 处理原始输入
			byte[] input;
			if (origin == null) {
				input = new byte[0];
			} else if (charsetname == null || charsetname.isEmpty()) {
				input = origin.getBytes();
			} else {
				input = origin.getBytes(charsetname);
			}

			// 先更新盐值到消息摘要
			md.update(salt);
			// 再更新原始数据
			md.update(input);
			// 完成哈希计算
			byte[] digest = md.digest();

			// 拼接盐值和哈希结果（盐值需要一同存储用于后续验证）
			// 使用Base64编码盐值，便于存储和传输
			String saltStr = Base64.getEncoder().encodeToString(salt);
			String digestStr = byteArrayToHexString(digest);

			// 格式：盐值$哈希值
			return saltStr + "$" + digestStr;
		} catch (Exception e) {
			// 建议替换为日志输出
			log.error("MD5Encode error:", e);
			return null;
		}
	}

	/**
	 * 获取文件 MD5 值并自动生成随机salt（用于签名、认证用途）
	 */
	public static String fileToMD5(InputStream inputStream) throws IOException, NoSuchAlgorithmException {
		byte[] salt = generateSalt();
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] buffer = new byte[8192];
		int len;

		// 先更新文件内容
		while ((len = inputStream.read(buffer)) != -1) {
			md.update(buffer, 0, len);
		}

		// 再更新盐值
		md.update(salt);

		inputStream.close();
		byte[] digest = md.digest();

		// 拼接盐值和哈希结果
		String saltStr = Base64.getEncoder().encodeToString(salt);
		String digestStr = fixedHex(digest);
		return saltStr + "$" + digestStr;
	}


	/**
	 * byte[] 转十六进制字符串
	 */
	public static String byteArrayToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder(bytes.length * 2);
		for (byte b : bytes) {
			sb.append(byteToHexString(b));
		}
		return sb.toString();
	}

	private static String byteToHexString(byte b) {
		int n = b < 0 ? b + 256 : b;
		return hexDigits[n / 16] + hexDigits[n % 16];
	}

	/**
	 * 使用 BigInteger 输出固定长度的 hex 字符串（补零至32位）
	 */
	private static String fixedHex(byte[] bytes) {
		BigInteger bi = new BigInteger(1, bytes);
		String hash = bi.toString(16);
		while (hash.length() < 32) {
			hash = "0" + hash;
		}
		return hash;
	}

}
